/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tasks;

import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;

import tools.Format;
import tools.Utils;
import core.Executor;
import core.Message;
import core.Peer;
import core.Torrent;
import core.TorrentManager;

/**
 *
 * @author Daisuke
 */
public class RequestPeer implements Runnable {

	private Torrent torrent;
	private Peer peer;
	private ExecutorService executor;
	private int nbPieces;

	public RequestPeer(Torrent torrent, Peer peer) {
		this.torrent = torrent;
		this.peer = peer;
		this.executor = Executor.getThreadPool();
		this.nbPieces = this.torrent.getPieces().length/20;
	}

	@Override
	public void run() {
		this.executor.execute(new SendHandshake(peer,this.torrent.getHashInfo()));
		ReadHandshake readhandshake = new ReadHandshake(peer);
		try {
			if (readhandshake.readHanshake()) { 
				this.executor.execute(new ReadMessage(peer, torrent));
				this.executor.execute(new SendMessage(new Message(1,this.peer.getOutput())));
				this.executor.execute(new SendMessage(new Message(5, this.torrent.getBitfield(), this.peer.getOutput())));

	            this.executor.execute(new SendMessage(new Message(2,this.peer.getOutput())));
				int chosenPiece;
				byte[] byteLength, byteIndex, byteBegin = Format.intToByteArray(0), payload;				

				try {
					Thread.sleep(500);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}

				while ((chosenPiece = choosePiece()) != -1 && !this.peer.getSocket().isClosed() ) {                	
					if (!this.peer.isChoked()) {
						byteIndex = Format.intToByteArray(chosenPiece);
						
						if ((this.nbPieces) - 1 == chosenPiece) {
							byteLength = Format.intToByteArray((int) (this.torrent.getLength() - (this.torrent.getPieceLength() * ((this.nbPieces) - 1))));
						} else {
							byteLength = Format.intToByteArray(this.torrent.getPieceLength());
						}
						payload = Utils.concat(byteIndex, Utils.concat(byteBegin, byteLength));
						this.executor.execute(new SendMessage(new Message(6, payload, this.peer.getOutput())));
					}

					try {
						Thread.sleep(75);
					} catch (InterruptedException e) {						
						e.printStackTrace();
					}
				}

				this.executor.execute(new SendMessage(new Message(3,this.peer.getOutput())));

			}
		} catch (IOException ex) {
			System.out.println("RequestPeer|IOException: "+ex);
		} catch (Exception e) {
			System.out.println("RequestPeer|Exception: "+e);
		}
	}

	private int choosePiece() {
		if (Arrays.equals(this.torrent.getBitfield(), this.peer.getBitfield())) {
			return -1;
		} else {
			byte[] bitfield = this.torrent.getBitfield();
			byte[] bitfieldPeer = this.peer.getBitfield();
			
			for (int i = 0; i < this.nbPieces; i++) {
				if (Utils.getBit(bitfield, i) == 0 && Utils.getBit(bitfieldPeer, i) == 1) {
					return i;                    
				}
			}
		}
		return -1;
	}
}
